package gre.ui;

import gre.core.*;
import gre.db.*;
import java.io.*;
import java.sql.*;
import java.util.*;

/**
 *
 * @author nacuong
 */
public class TextUI {

  static final int questionsNo = 10;

  public static void main(String[] args) throws SQLException, IOException {
    /* establish connection to mysql */
    Connection connection = DBCreator.getConnection();
    Statement stmt = connection.createStatement();

    /* create database in demand */
    if (firstTimeUsed()) {
      System.out.println("First time using GRE Test Generator. Please wait for creating database...");
      DBCreator.createDatabase(stmt);
    }

    welcomeMessage();

    while (true) {
      Scanner sc = new Scanner(System.in);
      try {
        int mode = sc.nextInt();
        if (mode == 1) {
          doTest(stmt, 10);
        } else if (mode == 2) {
          insertData(stmt);
        } else if (mode == 3) {
          showData(stmt);
        } else if (mode == 4) {
          break;
        } else {
          System.out.println("Cannot recognize command");
        }
      } catch (Exception e) {
        System.out.println("Cannot recognize command");
      } finally {
        continueMessage();
      }
    }

  }

  /**
   * Check whether the software is used for first time
   * @return true if the software is used for first time; false otherwise
   */
  public static boolean firstTimeUsed() {
    try {
      Connection connection = DBCreator.getConnection();
      Statement stmt = connection.createStatement();
      stmt.executeQuery("SELECT wid,word,meaning FROM words");
      stmt.executeQuery("SELECT wid,sentence FROM sentences");
      connection.close();
      return false;
    } catch (SQLException e) {
      return true;
    }
  }

  public static void welcomeMessage() {
    System.out.println("Welcome to GRE Verbal Test Generator.");
    System.out.println("To start, please select a mode:");
    System.out.println("1) Practicing Mode\t\t2) Inserting Data Mode\t\t3) Showing Data Mode\t\t4) Exit");
  }

  public static void continueMessage() {
    System.out.println("To continue, please select a mode:");
    System.out.println("1) Practicing Mode\t\t2) Inserting Data Mode\t\t3) Showing Data Mode\t\t4) Exit");
  }

  /**
   * Text UI for testing mode
   * @param stmt
   * @throws SQLException
   */
  public static void doTest(Statement stmt, int questionsNo) throws SQLException {
    System.out.println("\n---- Praciticing Mode ----");
    Vector<Integer> wordIds = TestGenerator.generateWordIds(stmt, questionsNo);
    Vector<String> words = TestGenerator.generateWords(stmt, wordIds);
    Vector<String[]> sentences = TestGenerator.generateSentences(stmt, wordIds);
    Vector<String> questions = TestGenerator.generateQuestions(sentences);
    Vector<String> answers = TestGenerator.generateAnswers(sentences);

    boolean next = true;

    while (next) {
      /* print out word lists */
      System.out.println("Given the following words: ");
      for (String word : words) {
        System.out.print(word + ", ");
      }

      /* print out questions */

      int marks = 0;
      System.out.println("\n\nMatch synonyms or fill in the following sentences:");
      for (int inx = 1; inx <= questions.size(); inx++) {
        System.out.println(inx + ") " + questions.get(inx - 1));
        Scanner sc = new Scanner(System.in);
        System.out.print("Asnwer: ");
        String answer = answers.get(inx - 1);
        String yourAnswer = sc.nextLine();
        if (yourAnswer.equals(answer)) {
          System.out.println("CORRECT!");
          marks++;
        } else {
          System.out.println("WRONG! The correct answer is " + answer);
        }
      }

      /* print out resutls */
      System.out.println("Your final scores: " + marks + "/" + answers.size());

      /* ask for continuing */
      System.out.print("Do you want to continue (yes|no): ");
      Scanner sc = new Scanner(System.in);
      next = sc.nextLine().trim().toLowerCase().equals("yes");
    }
  }

  /**
   * Text UI for word insertion mode
   * @param stmt
   * @throws SQLException
   */
  public static void insertData(Statement stmt) throws SQLException, IOException {
    System.out.println("\n----Insert Data Mode----");
    System.out.println("You can provide either a data file or typing the data here.\n");
    System.out.println("Each data should be inserted in the form:");
    System.out.println("word|meaning|sentence1@sentence2@sentence3\n");
    System.out.println("Each file sould be inserted in the form: file:file_path");
    System.out.println("Each line in file should be in the data form mentioned above.\n");
    System.out.println("Ending modifying mode with the command:: STOP\n");

    Scanner sc = new Scanner(System.in);
    String data = sc.nextLine();
    while (!data.toLowerCase().equals("stop")) {
      /* inserting from file */
      if (data.startsWith("file:")) {
        try {
          String filePath = data.replaceFirst("file:", "");
          WordInserter.insertFormFile(stmt, filePath);
          System.out.println("Successfully inserting.");
        } catch (ArrayIndexOutOfBoundsException e) {
          System.out.println("Unsuccessully inserting data." + data + "cannot be found.");
        } catch (IOException e) {
          System.out.println("Unsuccessully inserting data." + data + "cannot be found.");
        }
      } /* inserting from data string */ else {
        WordInserter.insert(stmt, data, true, true);
        System.out.println("Successully inserting data.\n");
      }

      /* ask for more data */
      System.out.println("Insert data:");
      data = sc.nextLine();
    }
  }

  /**
   * Text UI for word displaying mode
   * @param stmt
   */
  public static void showData(Statement stmt) throws SQLException {
    System.out.println("\n----Browse Data Mode----");
    System.out.println("Some commands: \"-all\" to display all; \"-reg word\" to search for regular expression \"word\"; \"word\" "
            + "to search for \"word\".\nModify mode is only triggered when searching with single \"word\".\n");
    System.out.println("Ending modifying mode with the command: STOP\n");
    System.out.print("Search: ");
    Scanner sc = new Scanner(System.in);
    String word = sc.nextLine().trim();

    while (!word.toLowerCase().equals("stop")) {
      if (word.equals("-all")) {
        /* display all mode */
        showAllWords(stmt);
      } else if (!word.contains(" ")) {
        /* display single word mode */
        int wordId = showSingleWord(stmt, word);
        modifyData(stmt, wordId);
      } else {
        /* display regular expression word mode */
        showRegularWords(stmt, word);
      }

      System.out.print("Search: ");
      sc = new Scanner(System.in);
      word = sc.nextLine().trim();
    }
  }

  /**
   * Display data of a single word
   * @param stmt
   * @param word
   * @return
   * @throws SQLException
   */
  public static int showSingleWord(Statement stmt, String word) throws SQLException {
    Vector<String> data = WordSelector.selectWord(stmt, word);
    System.out.println(WordSelector.displayWord(data));

    return DBSelector.selectId(stmt, word);
  }

  /**
   * Display all words in database
   * @param stmt
   * @throws SQLException
   */
  public static void showAllWords(Statement stmt) throws SQLException {
    Vector<Vector<String>> datas = WordSelector.selectAll(stmt);
    for (Vector<String> data : datas) {
      System.out.println(WordSelector.displayWord(data));
    }
  }

  /**
   * Display data of regular expression words
   * @param stmt
   * @param word
   * @throws SQLException
   */
  public static void showRegularWords(Statement stmt, String word) throws SQLException {
    String[] split = word.split(" ");
    if (split.length >= 2) {
      String first = split[0];
      String second = split[1];
      if (first.equals("-reg")) {
        Vector<Vector<String>> datas = WordSelector.selectAll(stmt);
        for (Vector<String> data : datas) {
          if (!data.isEmpty()) {
            String dataWord = data.get(0);
            if (dataWord.matches(second)) {
              System.out.println(WordSelector.displayWord(data));
            }
          }
        }
      } else {
        System.out.println("Cannot recognize command.");
      }
    } else {
      System.out.println("Cannot find thid word.");
    }
  }

  /**
   * Text UI for word modifying mode
   * @param stmt
   */
  public static void modifyData(Statement stmt, int wordId) throws SQLException {
    System.out.println("Modify the above word with the following command:");
    System.out.println("mod [-word new_word] [-meaning new_meaning] [-sentence id new_sentence]");
    System.out.println("Add new sentence with the following command:");
    System.out.println("add sentence1[@setence]*");
    System.out.println("Ending modifying mode with the command: STOP");
    Scanner sc = new Scanner(System.in);
    String commands = sc.nextLine().trim();
    while (!commands.toLowerCase().equals("stop")) {
      String[] split = commands.split(" ");
      String command = split[0];
      if (command.equals("mod")) {
        executeModifyCommand(stmt, wordId, split);
      } else if (command.equals("add")) {
        executeAddCommand(stmt, wordId, split);
      } else {
        System.out.println("Cannot recognize command.");
      }

      System.out.print("Command: ");
      commands = sc.nextLine().trim();
    }
  }

  /**
   * Execute modify word command in form of mod [-word new_word] [-meaning new_meaning] [-sentence id new_sentence]
   * @param stmt
   * @param wordId
   * @param commands
   * @throws SQLException
   */
  public static void executeModifyCommand(Statement stmt, int wordId, String[] commands) throws SQLException {
    int inx = 1;
    while (inx < commands.length) {
      String command = commands[inx];
      if (command.equals("-word") && inx <= commands.length - 1) {
        inx++;
        String newWord = commands[inx];
        stmt.executeUpdate("UPDATE words SET word='" + newWord + "' WHERE wid=" + wordId);
        System.out.println("Successfully modifying word");
      } else if (command.equals("-meaning") && inx <= commands.length - 1) {
        inx++;
        String newMeaning = "";
        for (; inx < commands.length; inx++) {
          if (!commands[inx].equals("-word") && !commands[inx].equals("-sentence")) {
            newMeaning += commands[inx] + " ";
          } else {
            inx--;
            break;
          }
        }
        newMeaning = newMeaning.trim().replaceAll("'", "");
        System.out.println(newMeaning);
        System.out.println("UPDATE words SET meaning='" + newMeaning + "' WHERE wid=" + wordId);
        stmt.executeUpdate("UPDATE words SET meaning='" + newMeaning + "' WHERE wid=" + wordId);
        System.out.println("Successfully modifying meaning");
      } else if (command.equals("-sentence") && inx <= commands.length - 2) {
        try {
          inx++;
          int sentenceId = Integer.parseInt(commands[inx]);
          System.out.println(sentenceId); // testing
          String oldSentence = DBSelector.selectStatement(stmt, wordId).get(sentenceId - 1);
          System.out.println(oldSentence); // testing
          String newSentence = "";
          inx++;
          for (; inx < commands.length; inx++) {
            if (!commands[inx].equals("-word") && !commands[inx].equals("-meaning")) {
              newSentence += commands[inx] + " ";
            } else {
              inx--;
              break;
            }
          }
          newSentence = newSentence.trim().replaceAll("'", "");
          System.out.println(newSentence); // testing
          stmt.executeUpdate("UPDATE sentences SET sentence='" + newSentence + "' WHERE wid=" + wordId + " AND sentence='"
                  + oldSentence + "'");
        } catch (Exception e) {
          System.out.println("Cannot recognize sentence command.");
          inx++;
        }
      } else {
        inx++;
      }
    }
  }

  /**
   * Execute adding sentence command in form of add sentence1[@setence]*
   * @param stmt
   * @param wordId
   * @param command
   * @throws SQLException
   */
  public static void executeAddCommand(Statement stmt, int wordId, String[] command) throws SQLException {
    String[] sentences = command[1].split("@");
    String word = DBSelector.selectWord(stmt, wordId);
    for (String sentence : sentences) {
      DBInserter.insertSentence(stmt, word, sentence);
    }
    System.out.println("Successfully adding sentences");
  }
}
